Python Operator Overloading

    In this tutorial, we will discuss python operator overloading and also learn different magical methods which change the operator meaning.

    What is Operator Overloading in Python?

    In python, the same operator can perform different operations on different objects and there are many predefined operators in python. For example, the + operator can perform arithmetic addition between two numbers while it performs concatenation between two strings. Operator overloading is a technique of performing different operations with the same operator, on different objects. Python has inbuilt Operators overloading that means they are supposed to operate between the objects as per defined in the in-built classes.

    Example:

    class ClassName:
        def __init__(self, a,b):
            self.a=a
            self.b=b
    c = ClassName(10,20)
    d= ClassName(40,50)
    add = c+d

    Output:

    TypeError: unsupported operand type(s) for +: 'ClassName' and 'ClassName' 

    Behind the code

    We got an error in the above code because the + operator has no pre-defined statement, how to operate between two classes objects, that’s why we got an unsupported operand type error.

    Special function in Python:

    In python the class methods, which name start and end with double underscore __ are known as a special function or magical methods.  The class constructor __init__() is one of those special functions and there are many other special functions defined in python. Let’s discuss one more special function __str__() The __str__() method in class used to print some valuable information about the object when the user use the print(object_name) statement:

    Example:

    class ClassName:
        def __init__(self, a,b):
            self.a=a
            self.b=b
        def __str__(self):
            return "This what you get when you print its object"
    c = ClassName(10,20)
    print("-------when we use the print(c) statement-------")
    print(c)                 # it is equivalent to c.__str__()
    print("\n -------when we use the c.__str__() statement------")
    print(c.__str__())

    Output:

    -------when we use the print(c) statement-------
    This what you get when you print its object
    
     -------when we use the c.__str__() statement------
    This what you get when you print its object

    Behind the scene

    In the above code, we can see that when we print the object of the class it print the statement of __str__() method.

    Operator overloading with the + operator

    We can overload the + operator using special function __add__() and can make the + operator to perform some specific task.

    For example:

    class ClassName:
        def __init__(self, a,b):
            self.a=a
            self.b=b
        def __str__(self):
            return "This what you get when you print its object"
        def __add__(self,next):                 # Here self is c_1 and next is c_2
            a = self.a+next.a
            b = self.b+next.b
            return (a,b)
    
    c_1 = ClassName(10,20)
    c_2 = ClassName(30,20)
    print("-------when we use the c_1 + c_2 statement-------")
    print(c_1 + c_2)                 # it is equivalent to c_1.__add__(c2)
    print("\n -------when we use the c_1.__add__(c_2) statement------")
    print(c_1.__add__(c_2))

    Output:

    -------when we use the c_1 + c_2 statement-------
    (40, 40)
     -------when we use the c_1.__add__(c_2) statement------
    (40, 40)

    Behind the code

    In the above code, we defined a special function __add__() which set the task for + operator. Like arithmetic + operator need two numbers to add, same here we created two object c_1 and c_2.

    Arithmetic Special functions

    Operation Expression Equivalent
    Addition c_1 + c_2 c_1.__add__(c_2)
    Subtraction c_1 - c_2 c_1.__sub__(c_2)
    Multiplication c_1 * c_2 c_1.__mul__(c_2)
    Power c_1 ** c_2 c_1.__pow__(c_2)
    Division c_1 / c_2 c_1.__truediv__(c_2)
    Floor Division c_1 // c_2 c_1.__floordiv__(c_2)
    Remainder c_1 % c_2 c_1.__mod__(c_2)
    Bitwise Left Shift c_1 << c_2 c_1.__lshift__(c_2)
    Bitwise Right Shift c_1 >> c_2 c_1.__rshift__(c_2)
    Bitwise AND c_1 & c_2 c_1.__and__(c_2)
    Bitwise OR c_1 | c_2 c_1.__or__(c_2)
    Bitwise XOR c_1 ^ c_2 c_1.__xor__(c_2)
    Bitwise NOT ~c_2 c_1.__invert__()

    Comparison Operator Overloading

    Like arithmetic operator, we can overload comparison operators.

    Operation Expression Equivalent
    Less than c_1 < c_2 c_1.__lt__(c_2)
    Less than or equal to c_1 <= c_2 c_1.__le__(c_2)
    Equal to c_1 == c_2 c_1.__eq__(c_2)
    Not equal to c_1 != c_2 c_1.__ne__(c_2)
    Greater than c_1 > c_2 c_1.__gt__(c_2)
    Greater than or equal to c_1 >= c_2 c_1.__ge__(c_2)

    Example:

    class ClassName:
        def __init__(self, a,b):
            self.a=a
            self.b=b
        def __str__(self):
            return "This what you get when you print its object"
    
        def __add__(self,next):
            a = self.a+next.a
            b = self.b+next.b
            return (a,b)
    
        def __gt__(self,next):
            if self.a + self.b > next.a+next.b:
                return True
            else:
                return False
    
    c_1 = ClassName(10,50)
    c_2 = ClassName(30,10)
    print("-------when we use the c_1 > c_2 statement-------")
    print(c_1 > c_2)                 # it is equivalent to c_1.__gt__(c2)
    print("\n -------when we use the c_1.__gt__(c_2) statement------")
    print(c_1.__gt__(c_2))

    Output:

    -------when we use the c_1 > c_2 statement-------
    True
     -------when we use the c_1.__gt__(c_2) statement------
    True